package registry

import (
	"fmt"
	"github.com/robfig/cron/v3"
	"go.uber.org/zap"
	"monitor-agent/configs"
	. "monitor-agent/internal/report"
	"monitor-agent/internal/utils"
	"monitor-agent/pkg/logging"
	"net"
)

const (
	// client fetch interval, unit: second
	specFmtReportInterval = "@every %ds"
)

var ctrl struct {
	RClient  ReportServerClient
	CronCore *cron.Cron
	CronFunc func()

	Setting *AgentSetting
	IsLocal bool
}

var defSetting = &AgentSetting{
	ReportInterval: 60,
	ResendTimes:    1,
	FetchTimeout:   2,
	Settings:       []string{},
}

func InitController(fc func(), rc ReportServerClient, isLoc bool) error {
	ctrl.CronFunc = fc
	ctrl.RClient = rc
	ctrl.IsLocal = isLoc
	ctrl.Setting = defSetting
	return UpdateReportInterval(ctrl.Setting)
}

func ResetController() {
	isLocal := !utils.IsPublicIP(net.ParseIP(configs.Config.GRPC.BackendAddr))
	err := InitController(ctrl.CronFunc, ctrl.RClient, isLocal)
	if err != nil {
		logging.Logger().Fatal("failed to reset controller", zap.Error(err))
	}
}

func UpdateReportInterval(st *AgentSetting) (err error) {
	if ctrl.CronCore != nil {
		ctrl.CronCore.Stop()
	}
	ctrl.CronCore = cron.New()
	_, err = ctrl.CronCore.AddFunc(fmt.Sprintf(specFmtReportInterval, st.ReportInterval), ctrl.CronFunc)
	if err != nil {
		return err
	}
	go func() {
		logging.Logger().Info(fmt.Sprintf("start report to monitor-backend, ip: %s", configs.Config.GRPC.BackendAddr))
		ctrl.CronCore.Run()
	}()
	return
}

func GetSetting() *AgentSetting {
	return ctrl.Setting
}

func SetSetting(st *AgentSetting) {
	if ctrl.Setting.ReportInterval != st.ReportInterval {
		if err := UpdateReportInterval(st); err != nil {
			ResetController()
			return
		}
	}
	ctrl.Setting = st
}

func GetReportClient() ReportServerClient {
	return ctrl.RClient
}

func GetIPStatus() bool {
	return ctrl.IsLocal
}
